/*
 * This source code is part of TWaver 4.0
 *
 * Serva Software PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 * Copyright 2002 - 2011 Serva Software. All rights reserved.
 */

package demo.editor.pipe.element;

import java.awt.BasicStroke;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import twaver.Element;
import twaver.TUIManager;
import twaver.TWaverConst;
import twaver.TWaverUtil;
import twaver.base.Direction;
import demo.editor.pipe.Const;
import demo.editor.pipe.ui.SquarePipeUI;

public class SquarePipe extends AbstractPipe {
	
	private List cellCounts = new ArrayList();

	public SquarePipe(){
		super();
		init();
	}
	
	public SquarePipe(Object id){
		super(id);
		init();
	}
	
	private void init(){
    	this.setName("SquarePipe");
    	this.setSize(160, 160);
		this.putCustomDrawShapeFactory(TWaverConst.SHAPE_RECTANGLE);
		this.putCustomDrawGradientFactory(TWaverConst.GRADIENT_LINE_NW);
    	this.putClientProperty(Const.PROPERTYNAME_SQUAREPIPE_DIRECTION, Direction.HORIZONTAL);
		this.setIcon("/demo/editor/pipe/element/PipeHole.png");
    	this.fireCellCountsChange();
	}
	
	public List getCellCounts() {
		return cellCounts;
	}

	public void setCellCounts(List cellCounts) {
		if(this.cellCounts == null){
			this.cellCounts = new ArrayList();
		}
		this.cellCounts = cellCounts;
		this.fireCellCountsChange();
		if(this.cellCounts.size() > 0){
			this.setIcon("/demo/editor/pipe/element/SquarePipe.png");
		}else{
			this.setIcon("/demo/editor/pipe/element/PipeHole.png");
		}
	}
	
	public void fireCellCountsChange(){
		this.firePropertyChange(Const.PROPERTYNAME_SQUAREPIPE_CELLCOUNTS, null, cellCounts);
	}
	
    public String getUIClassID() {
        return SquarePipeUI.class.getName();
    }
    
    public void addCells(int index, int count){
    	if(index <=0 || index >= cellCounts.size()){
    		return;
    	}
    	int start = 0;
    	for(int i=0; i<=index; i++){
    		Integer rowCount = (Integer)cellCounts.get(i);
    		start += rowCount.intValue();
    	}
		Iterator it = this.getChildren().iterator();
		while(it.hasNext()){
			Element child = (Element)it.next();
			if(child instanceof IPipe){
				IPipe hole = (IPipe)child;
				if(hole.getHoleIndex() >= start){
					hole.setHoleIndex(hole.getHoleIndex() + count);
				}
			}
		}
    	int value = ((Integer)cellCounts.get(index)).intValue();
    	cellCounts.set(index, TWaverUtil.valueOf(value + count));
    	this.fireCellCountsChange();
    }
    
    public void removeCells(int index, int count){
    	if(index <=0 || index >= cellCounts.size()){
    		return;
    	}
    	int start = 0;
    	for(int i=0; i<=index; i++){
    		Integer rowCount = (Integer)cellCounts.get(i);
    		start += rowCount.intValue();
    	}
    	int descCount = count;
    	int value = ((Integer)cellCounts.get(index)).intValue();
    	if(value <= count){
    		descCount = value;
    		cellCounts.remove(index);
    	}else{
        	cellCounts.set(index, TWaverUtil.valueOf(value - count));
    	}
		Iterator it = this.getChildren().iterator();
		while(it.hasNext()){
			Element child = (Element)it.next();
			if(child instanceof IPipe){
				IPipe hole = (IPipe)child;
				if(hole.getHoleIndex() >= start){
					hole.setHoleIndex(hole.getHoleIndex() - descCount);
				}
			}
		}
    	this.fireCellCountsChange();
    }

	public Rectangle getPipeHoleBoundsByHoleIndex(int cellIndex){
    	if(cellIndex < 0 || cellIndex >= getAllCellCount()){
    		return null;
    	}
    	final int row = this.getRowIndexByCellIndex(cellIndex);
    	final int column = this.getColumnIndexByCellIndex(cellIndex);
    	if(row < 0 || column < 0){
    		return null;
    	}
    	
    	Point location = this.getLocation();
    	int borderWidth = 0;
    	Stroke stroke = this.getCustomDrawOutlineStroke();
    	if(stroke instanceof BasicStroke){
    		borderWidth = (int)((BasicStroke)stroke).getLineWidth();
    	}
    	int x = location.x + borderWidth;
    	int y = location.y + borderWidth;
    	int w = this.getWidth() - borderWidth * 2;
    	int h = this.getHeight() - borderWidth * 2;
    	
		Rectangle rect = new Rectangle();
    	if(this.isHorizontal()){
    		Integer rowCount = (Integer)this.cellCounts.get(row);
    		rect.width = (int)(w / (double)rowCount.intValue());
    		rect.height = (int)(h / (double)this.cellCounts.size());
    		rect.x = (int)(x + column * w / (double)rowCount.intValue());
    		rect.y = (int)(y + row * h / (double)this.cellCounts.size());
    	}else{
    		Integer columnCount = (Integer)this.cellCounts.get(column);
    		rect.width = (int)(w / (double)this.cellCounts.size());
    		rect.height = (int)(h / (double)columnCount.intValue());
    		rect.x = (int)(x + column * w / (double)this.cellCounts.size());
    		rect.y = (int)(y + row * h / (double)columnCount.intValue());
    	}
    	stroke = TUIManager.getStrokeByType(this.getInnerStroke());
    	if(stroke instanceof BasicStroke){
	    	int innerBorder = (int)(-1 * ((BasicStroke)stroke).getLineWidth());
	    	rect.grow(innerBorder, innerBorder);
    	}
    	return rect;
	}
    
    public int getAllCellCount(){
    	int count = 0;
    	for(int i=0; i<cellCounts.size(); i++){
    		Integer rowCount = (Integer)cellCounts.get(i);
    		count += rowCount.intValue();
    	}
    	return count;
    }
    
    public boolean isHorizontal(){
    	Object direction = this.getClientProperty(Const.PROPERTYNAME_SQUAREPIPE_DIRECTION);
    	return Direction.HORIZONTAL.equals(direction);
    }
    
    public int getRowIndexByPoint(int x, final int y){
    	int count = this.getAllCellCount();
    	for(int i=0; i<count; i++){
    		Rectangle rect = this.getPipeHoleBoundsByHoleIndex(i);
    		if(rect.contains(x, y)){
    			return this.getRowIndexByCellIndex(i);
    		}
    	}
    	return -1;
    }
    
    public int getRowIndexByCellIndex(int cellIndex){
    	if(cellIndex < 0 || cellIndex >= getAllCellCount()){
    		return -1;
    	}
    	int count = 0;
    	for(int i=0; i<cellCounts.size(); i++){
    		Integer rowCount = (Integer)cellCounts.get(i);
    		count += rowCount.intValue();
    		if(count >= cellIndex + 1){
    	    	if(isHorizontal()){
    	    		return i;
    	    	}else{
    	    		return rowCount.intValue() - (count - cellIndex);  
    	    	}
    		}
    	}
    	return -1;
    }
    
    public int getColumnIndexByPoint(int x, int y){
    	int count = this.getAllCellCount();
    	for(int i=0; i<count; i++){
    		Rectangle rect = this.getPipeHoleBoundsByHoleIndex(i);
    		if(rect.contains(x, y)){
    			return this.getColumnIndexByCellIndex(i);
    		}
    	}
    	return -1;
    }
    
    public int getColumnIndexByCellIndex(int cellIndex){
    	if(cellIndex < 0 || cellIndex >= getAllCellCount()){
    		return -1;
    	}
    	int count = 0;
    	for(int i=0; i<cellCounts.size(); i++){
    		Integer columnCount = (Integer)cellCounts.get(i);
    		count += columnCount.intValue();
    		if(count >= cellIndex + 1){
    	    	if(isHorizontal()){
    	    		return columnCount.intValue() - (count - cellIndex);  
    	    	}else{
    	    		return i;
    	    	}
    		}
    	}
    	return -1;
    }
}